﻿using System;
using LingDong.ConfigProvider;
using LingDong.DataProvider;
using LingDong.IndexCreator.Helper;
using LingDong.IndexEntities.Document;
using NLog;
using PanGu;

namespace LingDong.IndexCreator
{
    public class SubIndexCreator
    {
        #region Constructor

        public SubIndexCreator()
        {
            logger = LogManager.GetCurrentClassLogger();
            logger.Debug("SubIndexCreator Consturct.");
            try
            {
                logger.Debug("PanGu Segment Init.");
                Segment.Init();
            }
            catch (Exception ex)
            {
                logger.Error("Error in PanGu Segment Init: {0}", ex.Message);
                throw;
            }
        }

        #endregion
        

        #region Public Methods

        /// <summary>
        /// Create sub index from default data reader, the SougouTDataReader
        /// </summary>
        public void CreateSubIndex()
        {
            using (IDataReader dataReader = DataReaderFactory.CreateDataReader())
            {
                CreateSubIndex(dataReader);
            }
        }
        
        /// <summary>
        /// Create sub index from user specified data reader
        /// </summary>
        /// <param name="dataReader"></param>
        public void CreateSubIndex(IDataReader dataReader)
        {
            if (dataReader == null)
            {
                return;
            }

            try
            {
                logger.Debug("SubIndexCreator CreateSubIndex Began.");
                while (!dataReader.IsAllDataRead())
                {
                    logger.Debug("Init DocumentIndex.");
                    documentIndex = new DocumentIndex();
                    
                    logger.Debug("Init DictionaryIndex.");
                    dictionaryIndex = new DictionaryIndex();

                    logger.Debug("Create one sub index.");
                    CreateOneSubIndex(dataReader);

                    logger.Debug("Save one sub index to files.");
                    SaveIndexToFiles();
                }
                logger.Debug("SubIndexCreator CreateSubIndex Finished.");
            }
            catch (Exception ex)
            {
                Logger logger = LogManager.GetCurrentClassLogger();
                logger.Error("In subindex creator, CreateSubIndex: {0}", ex.Message);
                throw;
            }
        }

        #endregion
        

        #region Private Methods

        /// <summary>
        /// Process [documentNumPerIndex] documents each run
        /// </summary>
        /// <param name="dataReader"></param>
        private void CreateOneSubIndex(IDataReader dataReader)
        {
            for (int i = 0; i < ConfigIndex.Default.DocumentNumPerIndex; i++)
            {
                DataEntity data = dataReader.GetNextData();
                if (data == null)
                    break;

                OperateOneDocument(data, dataReader.IsDataContainsOnlyText());
            }

            dictionaryIndex.UpdateDictionaryInfo();
        }

        /// <summary>
        /// Process one document
        /// Add it's content to original document index and parsed document index
        /// Then save document offset to document index
        /// Add words appears in the document to inverted list, add words to dictionary
        /// </summary>
        /// <param name="data">the document</param>
        /// <param name="isDataContainsOnlyText"></param>
        private void OperateOneDocument(DataEntity data, bool isDataContainsOnlyText)
        {
            ParsedDocumentEntity document = documentIndex.Add(data.Url, data.Content, isDataContainsOnlyText);
            dictionaryIndex.AddDocument(document);
        }

        /// <summary>
        /// Save the sub index in main memery to files
        /// </summary>
        private void SaveIndexToFiles()
        {
            SubIndexNameHelper fileNameHelper = new SubIndexNameHelper();

            // inverted list & dictionary
            dictionaryIndex.SaveToFile(
                fileNameHelper.GetInvertedListFileName(),
                fileNameHelper.GetDictionaryFileName());

            // documents
            documentIndex.SaveToFile(
                fileNameHelper.GetDocumentIndexFileName(),
                fileNameHelper.GetParsedDocumentFileName(),
                fileNameHelper.GetOriginalDocumentFileName());
        }

        #endregion
        

        #region Private Members

        private DocumentIndex documentIndex;
        private DictionaryIndex dictionaryIndex;
        private Logger logger;

        #endregion
    }
}
